Reveal the impact of COVID-19 on the stock prices of top 40 companies in Singapore by market capitalisation.
Script stock prices of top 40 companies in Singapore by market capitalization between 1st January 2020 - 31st December 2021 by using tidyquant R package.
Using either calender heatmap or horizon graph, prepare a data visualization showing the historical stock prices by the top 40 companies in Singapore by market capitalization.
The code chunk below is to install the packages needed.
packages = c('tidyquant', 'tidyverse', 'ggHoriPlot', 'ggTimeSeries', 'kableExtra', 'ggthemes', 'plotly')
for(p in packages){library
if(!require(p, character.only = T)){
install.packages(p)
}
library(p, character.only = T)
}
The symbols of the top 40 companies in Singapore by market capitalization was downloaded as companiesmarketcap.com - Largest companies in Singapore by market capitalization.cs. This csv data was imported using below code.
symbol_table <- read_csv("data/companiesmarketcap.com - Largest companies in Singapore by market capitalization.csv") %>%
rename(symbol = Symbol)
Below code chunk is to script the stocks data from Yahoo Finance.
from_date = "2020-01-01"
to_date = "2021-12-01"
stock_selected = c(symbol_table$symbol[1:40])
Top40_Name = c(symbol_table$Name[1:40])
stock_data_daily = tq_get(stock_selected,
get = "stock.prices",
from = from_date,
to = to_date)
kable(head(stock_data_daily)) %>%
kable_styling()
| symbol | date | open | high | low | close | volume | adjusted |
|---|---|---|---|---|---|---|---|
| SE | 2020-01-02 | 41.00 | 41.190 | 39.460 | 40.04 | 5857000 | 40.04 |
| SE | 2020-01-03 | 39.44 | 40.650 | 39.400 | 40.49 | 5237800 | 40.49 |
| SE | 2020-01-06 | 40.07 | 41.030 | 40.029 | 40.48 | 4049200 | 40.48 |
| SE | 2020-01-07 | 40.50 | 41.800 | 40.350 | 41.01 | 3947600 | 41.01 |
| SE | 2020-01-08 | 41.00 | 41.389 | 40.055 | 40.16 | 3200800 | 40.16 |
| SE | 2020-01-09 | 40.79 | 40.900 | 40.040 | 40.53 | 3129700 | 40.53 |
Let’s now join ‘stock_data_daily’ with ‘symbol’ to include the company name in the data tibble.
stock_data_daily1 <- stock_data_daily %>%
left_join(symbol_table,
by = "symbol")
Next, we want to order the stock in descending order by the market capitalization value using order().
stock_data_daily1 <- stock_data_daily1[order(-stock_data_daily1$marketcap),]
Alternative method is as below:
stock_data_daily1 <- stock_data_daily1 %>%
mutate(Name = factor(Name, levels = Top40_Name)) %>%
arrange(Name)
kable(head(stock_data_daily1)) %>%
kable_styling()
| symbol | date | open | high | low | close | volume | adjusted | Rank | Name | marketcap | price (USD) | country |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| SE | 2020-01-02 | 41.00 | 41.190 | 39.460 | 40.04 | 5857000 | 40.04 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
| SE | 2020-01-03 | 39.44 | 40.650 | 39.400 | 40.49 | 5237800 | 40.49 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
| SE | 2020-01-06 | 40.07 | 41.030 | 40.029 | 40.48 | 4049200 | 40.48 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
| SE | 2020-01-07 | 40.50 | 41.800 | 40.350 | 41.01 | 3947600 | 41.01 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
| SE | 2020-01-08 | 41.00 | 41.389 | 40.055 | 40.16 | 3200800 | 40.16 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
| SE | 2020-01-09 | 40.79 | 40.900 | 40.040 | 40.53 | 3129700 | 40.53 | 1 | Sea (Garena) | 76666667008 | 137.46 | Singapore |
Now, our dataset ‘stock_data_daily1’ is ready for visualization.
A calendar heatmap is a great way to visualise daily data. Its structure makes it easy to detect weekly, monthly, or seasonal patterns.
We firstly create a function to make a calendar heatmap and set Name as the variable, so that we don’t need to repeat the steps when plotting for all the 40 companies. Later, we will loop through all the values in Name column to create the corresponding plots.
calendar_heatmap <- function(df, var) {
ggplot_calendar_heatmap(
df %>% filter(Name ==var),
'date',
'close',
dayBorderSize = 0.25,
dayBorderColour = "black",
monthBorderSize = 1,
monthBorderColour = "black",
monthBorderLineEnd = "round") +
xlab('') +
ylab('') +
labs(title = paste(var, "Stock Close Price (SGD/share)"))+
scale_fill_continuous(low = "red", high = "green")+
theme(plot.title = element_text(size = rel(1), hjust=0.5, face = "bold"),
panel.background = element_rect(fill = NA),
panel.grid.major = element_line(colour = "grey90"),
panel.border = element_rect(linetype = "solid", fill = NA),
strip.background = element_rect(colour = "black"),
strip.text.x = element_text(colour = "black", size = rel(1), face = "bold"),
legend.title = element_text(face = "bold"),
axis.text = element_text(colour = "black", size = rel(0.8), face = "bold"))
}
Next, we loop through Name var, create plots and store them in a list using purrr::map(). Then, we display all plots with purrr::walk().
plot_list <- unique(stock_data_daily1$Name) %>%
purrr::set_names() %>%
purrr::map( ~ calendar_heatmap(stock_data_daily1, .x))
purrr::walk(plot_list, print)
Below is to explore if above calendar heatmap works with ggplotly() to make it interactive. We can see that this interactive plot works.
p <- ggplot_calendar_heatmap(
stock_data_daily1 %>% filter(Name == 'DBS'),
'date',
'close',
dayBorderSize = 0.25,
dayBorderColour = "black",
monthBorderSize = 1,
monthBorderColour = "black",
monthBorderLineEnd = "round") +
xlab('') +
ylab('') +
labs(title = paste('DBS', "Stock Close Price (SGD/share)"))+
scale_fill_continuous(low = "red", high = "green")+
theme(plot.title = element_text(size = 8, hjust=0.5, face = "bold"),
panel.background = element_rect(fill = NA),
panel.grid.major = element_line(colour = "grey90"),
panel.border = element_rect(linetype = "solid", fill = NA),
strip.background = element_rect(colour = "black"),
strip.text.x = element_text(colour = "black", size = 8, face = "bold"),
legend.title = element_text(face = "bold"),
axis.text = element_text(colour = "black", size = 8, face = "bold"))
ggplotly(p, height = 250, width=900)
Horizon Graph compact the area chart by slicing it horizontally, and then then shifting the slices to baseline zero. It’s like a combo area chart and heatmap. The figure below shows a horizon plot using the ggHoriplot package.
ggplot() +
geom_horizon(aes(date, close),
data = stock_data_daily1,
origin = 'mean',
horizonscale = 6) +
scale_fill_hcl(palette = 'RdBu') +
facet_grid(Name~.)+
theme_few() +
theme(panel.spacing.y=unit(0, "lines"),
plot.title = element_text(size=13, face = "bold"),
plot.subtitle = element_text(size=9, face = "bold"),
strip.text.y = element_text(size = 9, angle = 0, hjust = 0, face = "bold"),
axis.text.y = element_blank(),
axis.text.x = element_text(size=9, angle = 90, face = "bold"),
axis.title.y = element_blank(),
axis.title.x = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(),
legend.position="none") +
scale_x_date(expand=c(0,0),
date_breaks = "1 month",
date_labels = "%b-%y",
limit=c(as.Date("2020-01-01"),as.Date("2021-12-31"))) +
ggtitle('Daily Stock Price of Top 40 Companies in Singapore (SGD/share), 2020 to 2021',
'Ranked by Market Capitalisation')
Below is to explore if above horizon graph works with ggplotly() wrapper to make it interactive.
H <- ggplot() +
geom_horizon(aes(date, close),
data = stock_data_daily1,
origin = 'mean',
horizonscale = 6) +
scale_fill_hcl(palette = 'RdBu') +
facet_grid(Name~.)+
theme_few() +
theme(panel.spacing.y=unit(0, "lines"),
plot.title = element_text(size=13, face = "bold"),
plot.subtitle = element_text(size=9, face = "bold"),
strip.text.y = element_text(size = 9, angle = 0, hjust = 0, face = "bold"),
axis.text.y = element_blank(),
axis.text.x = element_text(size=9, angle = 90, face = "bold"),
axis.title.y = element_blank(),
axis.title.x = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(),
legend.position="none") +
scale_x_date(expand=c(0,0),
date_breaks = "1 month",
date_labels = "%b-%y",
limit=c(as.Date("2020-01-01"),as.Date("2021-12-31"))) +
ggtitle('Daily Stock Price of Top 40 Companies in Singapore (SGD/share), 2020 to 2021',
'Ranked by Market Capitalisation')
ggplotly(H)
We can see that this interactive plot doesn’t work. Only x and y axis and title are displayed.
Using R to Scrape Financial Dataset
ggHoriPlot: build horizon plots in ggplot2